前面介紹的單機部署,是將前端、後端與 Nginx 都放在同一台 Server 上。
例如:
Server A
├── Nginx
├── Frontend
└── FastAPI
這種方式架構簡單,適合小型系統或初期開發。
但當系統規模逐漸增加後,通常會將前端與後端拆開部署,變成:
Frontend Server
├── Nginx
└── Frontend
Backend Server
├── Nginx
└── FastAPI
甚至可以使用不同網域:
Frontend
www.example.com
Backend API
api.example.com
此時前端與後端已經是兩個獨立服務。
假設使用者進入:
https://www.example.com
Request 會先到 Frontend Server。
Browser
│
│ GET https://www.example.com
▼
Frontend Nginx
│
▼
HTML / JavaScript / CSS
│
▼
Browser
瀏覽器取得前端程式後,開始執行 JavaScript。
這部分與單機部署沒有太大差別。
不同的是,當前端需要取得後端資料時,不再向同一台 Server 發送 Request,而是直接呼叫另一個 API Domain。
例如:
fetch("https://api.example.com/products")
因此 Request 流程變成:
Browser
│
│ GET https://api.example.com/products
▼
Backend Server
│
▼
Nginx
│
▼
FastAPI
│
▼
Database
FastAPI 查詢資料後,再回傳 JSON:
{
"data": [
{
"id": 1,
"name": "Product A",
"price": 1000
}
]
}
資料回傳流程則是:
Database
│
▼
FastAPI
│
│ JSON
▼
Backend Nginx
│
▼
Browser
│
▼
Frontend JavaScript
│
▼
更新畫面
因此完整架構可以表示成:
Internet
│
┌─────────┴─────────┐
│ │
▼ ▼
www.example.com api.example.com
│ │
▼ ▼
Frontend Nginx Backend Nginx
│ │
▼ ▼
HTML / JS / CSS FastAPI
│
▼
Database
前後端分離部署最大的好處,是讓不同服務可以獨立管理。
例如前端今天修改了一個按鈕樣式:
Frontend
v1.0 → v1.1
只需要重新部署 Frontend Server,不需要碰 Backend。
反過來,如果 FastAPI 修正了一個 API:
Backend
v2.3 → v2.4
也只需要更新 Backend Server。
因此:
Frontend Deploy
│
└── 不影響 Backend
Backend Deploy
│
└── 不需要重新部署 Frontend
另外,當流量增加時,也可以針對不同服務單獨擴充。
例如後端 API 壓力比較大,可以從:
1 台 Backend
增加為:
Backend 1
Backend 2
Backend 3
而前端可能仍然只需要一台 Server。
這就是服務拆分後的重要優勢之一。
前後端放在同一個 Domain 時,例如:
https://example.com
https://example.com/api
對瀏覽器來說通常屬於同一個 Origin。
但如果拆成:
https://www.example.com
https://api.example.com
這兩個網址的 Host 不同,因此屬於不同 Origin。
瀏覽器會套用 Same-Origin Policy。
所以 Backend 必須明確允許 Frontend Domain 存取 API。
FastAPI 可以使用 CORS Middleware:
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=[
"https://www.example.com"
],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
意思就是:
api.example.com
允許
www.example.com
呼叫 API
如果沒有正確設定 CORS,Browser 可能會出現:
Blocked by CORS policy
此時即使 Backend API 本身正常回應,Browser 仍可能阻擋前端 JavaScript 存取 Response。
前後端分離部署不代表一定要讓 Browser 直接呼叫:
api.example.com
另一種常見架構是:
www.example.com
仍然作為唯一入口。
Frontend Server 的 Nginx 可以設定:
location / {
root /var/www/frontend;
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://backend_server:8000;
}
這樣 Browser 依然只需要呼叫:
fetch("/api/products")
Request 流程則變成:
Browser
│
│ /api/products
▼
Frontend Nginx
│
│ Reverse Proxy
▼
Backend Server
│
▼
FastAPI
雖然 Frontend 與 Backend 實際上位於不同 Server,但對 Browser 而言仍然是:
https://www.example.com
這種設計有一個好處,就是可以減少前端直接面對跨 Origin 的問題。
如果採用不同 Domain:
User Browser
│
┌────────────┴────────────┐
│ │
▼ ▼
www.example.com api.example.com
│ │
▼ ▼
Frontend Nginx Backend Nginx
│ │
▼ ▼
Frontend Files FastAPI
│
▼
Database
如果採用 Nginx /api Reverse Proxy:
User Browser
│
▼
www.example.com
│
▼
Frontend Nginx
/ /api
│ │
▼ ▼
Frontend Backend Server
│
▼
FastAPI
│
▼
Database
因此,前後端分離真正的重點並不是「Domain 一定要分開」,而是:
Frontend 與 Backend 已經成為可以獨立部署、獨立更新與獨立擴充的服務。
從部署架構的角度來看,可以將演進過程理解成:
單機部署
Frontend + Backend
│
▼
前後端分離
Frontend Server
+
Backend Server
│
▼
多台 Backend
Frontend
│
Load Balancer
│
┌─┼─┐
▼ ▼ ▼
API API API
接下來當 Backend Server 從一台增加到多台時,就會開始遇到下一個部署概念:Load Balancer(負載平衡)。